﻿using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;

using Newtonsoft.Json;
using System;

using System.IO;
using System.IO.Compression;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Linq;
using NetCore.Model;
using NetCore.Log;

namespace NetCore.BLL
{
    /// <summary>
    /// 请求中转中间件
    /// </summary>
    public class RequestHandlingMiddleware
    {
        private readonly RequestDelegate next;

        public RequestHandlingMiddleware(RequestDelegate next)
        {
            this.next = next;
        }

        public async Task Invoke(HttpContext context)
        {
            if (!context.Response.HasStarted)
            {
                DateTime startDate = DateTime.Now;
                context.Request.EnableBuffering();
                string responseBody = "";
                int statusCode = 200;
                var httpContextModel = ApplicationEnvironments.DefaultSession.GetContextModel();
                try
                {
                 
                    if (File.Exists(ApplicationEnvironments.Site.HtmlDirectory + context.Request.Path) || File.Exists(ApplicationEnvironments.Site.HtmlDirectory + context.Request.Path + ".html"))
                    {
                        context.Response.StatusCode = 200;
                        await context.Response.WriteAsync(FileHelper.ReadLine(ApplicationEnvironments.Site.HtmlDirectory + context.Request.Path));
                    }
                    else
                    {
                        if (AppHttpContext.IsPost)//post请求记录信息
                        {
                            await next(context);
                           //httpContextModel.Result.Content = await this.ReadBodyAsync(context);//获取返回内容
                        }
                        else
                        {
                            await next(context);
                        }
                        httpContextModel.Result.StatusCode = context.Response.StatusCode;
                        httpContextModel.Result.ContentType = context.Response.ContentType;
                        httpContextModel.Result.Headers = context.Response.Headers;
                    }
                }
                catch (Exception ex)
                {
                    statusCode = 503;
                    responseBody = ex.Message;
                }
                finally
                {
                    if (statusCode == 401)
                    {
                        responseBody = "未授权";
                    }
                    else if (statusCode == 404)
                    {
                        responseBody = "未找到服务";
                    }
                    else if (statusCode == 502)
                    {
                        responseBody = "请求错误";
                    }
                    Regex regex = new Regex("^(2|3)\\d+$");
                    if (!regex.IsMatch(statusCode.ToString()) && !string.IsNullOrWhiteSpace(responseBody))
                    {
                        LogHelper.Error(this.GetType(), responseBody);
                        await HandleExceptionAsync(context, statusCode, responseBody);
                    }
                    AddLogger(httpContextModel);
                }
            }
        }

        private static Task HandleExceptionAsync(HttpContext context, int statusCode, string msg)
        {
          //  var data = new { code = statusCode.ToString(), is_success = false, msg = msg };
            var result = JsonConvert.SerializeObject(AjaxResult.Error(msg,statusCode));
            context.Response.ContentType = "application/json;charset=utf-8";
           
            return context.Response.WriteAsync(result);
        }
        /// <summary>
        /// 添加请求日志
        /// </summary>
        /// <param name="context">请求主体</param>
        /// <param name="statusCode">状态</param>
        /// <param name="startDate">时间</param>
        /// <param name="requestBody">请求内容</param>
        /// <param name="responseBody">相应内容</param>
        private static void AddLogger(HttpRequestLogModel context)
        {
            try
            {
                TimeSpan span = DateTime.Now - context.StartDate;
                context.Result.EndDate = DateTime.Now;
                context.Result.TaskTime = span.Milliseconds;
                LogHelper.RquestInfo(context);
            }
            catch (Exception ex)
            {
                LogHelper.Error(typeof(Exception), ex);
            }
        }


        public async Task<string> ReadBodyAsync(HttpContext context)
        {
            string responseBody = "";
            using (var swapStream = new MemoryStream())
            {
                var originalResponseBody = context.Response.Body;
                context.Response.Body = swapStream;
                await next(context);
                swapStream.Position = 0;
                //swapStream.Seek(0, SeekOrigin.Begin);
                try
                {
                    if (ApplicationEnvironments.Site.NoGetResponse == null || ApplicationEnvironments.Site.NoGetResponse.Where(x => x.ToLower().Equals(context.Response.ContentType.ToLower())).FirstOrDefault() == null)
                    {
                        var AcceptEncoding = context.Request.Headers["Accept-Encoding"].ToArray();
                        if (context.Request.Headers.ContainsKey("Accept-Encoding") && AcceptEncoding != null && AcceptEncoding.Length > 0)
                        {
                            AcceptEncoding = AcceptEncoding[0].Replace(" ", "").Split(',');
                            if (AcceptEncoding.Contains("br"))
                            {
                                using (var zipStream = new BrotliStream(swapStream, CompressionMode.Decompress, true))
                                {
                                    responseBody = new StreamReader(zipStream, Encoding.UTF8).ReadToEnd();
                                }
                            }
                            else if (AcceptEncoding.Contains("gzip"))
                            {
                                using (var zipStream = new GZipStream(swapStream, CompressionMode.Decompress, true))
                                {
                                    responseBody = new StreamReader(zipStream, Encoding.UTF8).ReadToEnd();
                                }
                            }
                            else if (AcceptEncoding.Contains("deflate"))
                            {
                                using (var zipStream = new DeflateStream(swapStream, CompressionMode.Decompress, true))
                                {
                                    responseBody = new StreamReader(zipStream, Encoding.UTF8).ReadToEnd();
                                }
                            }
                        }
                        else
                        {
                            responseBody = new StreamReader(swapStream, Encoding.UTF8).ReadToEnd();
                        }
                    }
                }
                catch (Exception ex)
                {
                    responseBody = ex.Message;
                }
                swapStream.Position = 0;
            //    swapStream.Seek(0, SeekOrigin.Begin);
                await swapStream.CopyToAsync(originalResponseBody);
                context.Response.Body = originalResponseBody;
            }
            return responseBody;
        }
    }

    public static class RequestHandlingExtensions
    {
        public static IApplicationBuilder UseRequestHandling(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<RequestHandlingMiddleware>();
        }
    }

}
